/**
 * Trabalho 2 
 * Sequencial 2 - Texto shakespe.txt 
 *
 * GRUPO 9 : Alfredo L. Porfirio
 *           Diego Gomes da Silva
 *           Marcos V. S. Ferreira
 *
 * Compile: g++ -o seq2 seq2.cpp 
 */

// Bibliotecas
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <sys/time.h>


// Ambiente
using namespace std;

// Contadores de palavras e frases palindromas
int n_pali_word = 0;
int n_pali_phrase = 0;


// Deixa as letras todas maisculas de uma string 

string toUpperCase(string s) {
    for (int i = 0; i < s.size(); i++)
        s[i] = toupper(s[i]);
    return s;
}

// Limpa a string de apontuacao, menos de ponto, exclamacao e interrogacao pois,
// definimos isso para separar em frases as sentencas
void remove_pontuacion(string& in) {
    for (int i = 0; i < in.length(); i++) {
        // ispunct é uma funcao da ctype.h que detecta se é alguma potuacao ja predefinida  
        if (in[i] != '.' && in[i] != '!' && in[i] != '?' && ispunct(in[i]))
            in[i] = ' '; // troca a pontuacao por espaco em branco
    }
    return;
}


// verifica se um string é palindromo, utilizando dos iterator da <string>

bool palindrome(string s) {
    if (equal(s.begin(), s.begin() + s.size() / 2, s.rbegin()))
        return true;
    else
        return false;
}

// remove o ultimo caracter da string caso seja pontuacao

string pop_back(string& in) {
    string out = in;
    if (ispunct(in[in.size() - 1])) {
        out = in.substr(0, in.size() - 1);
    }
    return out;
}

// mostra o ultimo caracter da string

char back(string& in) {
    return in[in.size() - 1];
}

// Pega a linha do aquivo e quebra em palavras e junta novamente em uma string(phrase) ate
// encontrar algum caracter especial que separe em frases, depois chama a pop_back para remover
// esse caracter e verificar se eh string

void token(string& in) {
    istringstream iss(in);
    string phrase;

    do {
        string sub;
        string aux;
        iss >> aux; // proxima palavra da linha

        aux = toUpperCase(aux);
        sub = pop_back(aux);
        if (sub.size() > 2 && palindrome(sub)) // Verifica se a palavra é palindromo 
            n_pali_word++;

        // verifica se nao chegou no final da frase
        if (back(aux) != '.' && back(aux) != '!' && back(aux) != '?' && iss) {
            phrase += sub; // incrementa a frase com a proxima palavra
        } else {

            phrase += sub; // incrementa a frase e compra se é palindrome

            //cout << phrase << endl;
            if (phrase.size() > 2 && palindrome(phrase)) // verifica se a frase eh palindromo 
                n_pali_phrase++;

            phrase.clear(); // limpa a frase para pegar a proxima
        }
    } while (iss);
}

// Variavel para ajudar a contar o tempo
#define MICRO_PER_SECOND 1000000 


// Funcao principal

int main() {
    // Estruturas pra contar o tempo
    struct timeval start_time;
    struct timeval stop_time;
    float time_diff;

    // variavel para pegar as linhas do arquivo que esta em fin
    string line;
    ifstream fin("shakespe.txt"); // ifstream = padrão ios:in
    if (fin.is_open()) {
        // contar o tempo para encontrar os palindromes
        gettimeofday(&start_time, NULL);
        while (!fin.eof()) //enquanto end of file for false continua
        {
            getline(fin, line, '\r'); // pega a linha ate encontar um '\r'(esse texto nao quebra linha com '\n')
            remove_pontuacion(line); // remove a pontuacao
            token(line); // conta os palindromos 
        }

        gettimeofday(&stop_time, NULL);
        time_diff = (float) (stop_time.tv_sec - start_time.tv_sec);
        time_diff += (stop_time.tv_usec - start_time.tv_usec) / (float) MICRO_PER_SECOND;
        printf("Calculo dos Palindromos em %f s\n", time_diff);
        // fecha o arquivo   
        fin.close();
    } else cout << "nao foi possivel abrir o arquivo.." << endl; // imprime msg de erro caso nao abra o arquivo 

    // print dos contadores
    cout << "Numero de Palavras Palindromas:  " << n_pali_word << endl;
    cout << "Numero de Frases Palindromas: " << n_pali_phrase << endl;

    return 0;
}